package net

import (
	"gitee.com/dennis-kk/service-box-go/util/errors"
	"github.com/panjf2000/gnet"
	"net"
	"sync/atomic"
)

const (
	BoxConnClose = iota
	BoxConnConnecting
)

//connection wrapper of gnet connection
type gnetConn struct {
	state int32
	conn  gnet.Conn
}

func (c *gnetConn) LocalAddr() (addr net.Addr) {
	if c.IsClose() {
		return nil
	}
	return c.conn.LocalAddr()
}
func (c *gnetConn) RemoteAddr() (addr net.Addr) {
	if c.IsClose() {
		return nil
	}
	return c.conn.RemoteAddr()
}

func (c *gnetConn) Read(b []byte) (n int, err error) {
	if c == nil {
		return 0, errors.ChannelHasClosed
	}

	if c.IsClose() {
		return 0, errors.ChannelHasClosed
	}

	length, buffer := c.conn.ReadN(len(b))
	copy(b, buffer)
	c.conn.ShiftN(length)
	return length, nil
}

func (c *gnetConn) Write(buf []byte) error {
	if c == nil || c.conn == nil {
		return errors.ChannelHasClosed
	}

	if c.IsClose() {
		return errors.ChannelHasClosed
	}

	return c.conn.AsyncWrite(buf)
}

func (c *gnetConn) Close() error {
	return c.conn.Close()
}

func (c *gnetConn) IsClose() bool {
	return atomic.LoadInt32(&c.state) == BoxConnClose
}

func (c *gnetConn) OnClose() {
	atomic.StoreInt32(&c.state, BoxConnClose)
}

func makeGnetConn(v interface{}) IBoxConn {
	if c, ok := v.(gnet.Conn); ok {
		return &gnetConn{
			state: BoxConnConnecting,
			conn:  c,
		}
	}
	return nil
}
